package neptune.web.server.services;

import it.robertobifulco.ias.Operation;

import javax.servlet.http.HttpSession;

import neptune.manager.NeptuneManager;
import neptune.manager.model.cluster.Cluster;
import neptune.manager.model.cluster.PhysicalNode;
import neptune.web.client.model.cluster.SerializableCluster;
import neptune.web.client.model.cluster.SerializablePhysicalNode;
import neptune.web.client.services.ClusterService;
import neptune.web.client.services.SecurityException;
import neptune.web.server.ApplicationManager;
import neptune.web.server.Debug;
import neptune.web.server.operations.AddPhysicalMachine;
import neptune.web.server.operations.EditPhysicalMachine;
import neptune.web.server.operations.GetCluster;
import neptune.web.server.operations.GetPhysicalMachine;
import neptune.web.server.operations.GetTask;
import neptune.web.server.operations.GetVMsHostedOnPm;
import neptune.web.server.operations.GetXenStatistic;
import neptune.web.server.operations.PauseNode;
import neptune.web.server.operations.RebootNode;
import neptune.web.server.operations.RemoveAllFinishedJobs;
import neptune.web.server.operations.RemovePhysicalMachine;
import neptune.web.server.operations.SaveNodeAsTemplate;
import neptune.web.server.operations.StartNode;
import neptune.web.server.security.SecurityHelper;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class ClusterServiceImpl extends RemoteServiceServlet implements
		ClusterService {

	/**
	 * 
	 */
	private static final long serialVersionUID = -1876664222938270227L;

	/**
	 * Aggiunge una macchina fisica al cluster
	 */
	public Boolean addPhysicalMachine(
			SerializablePhysicalNode serializablePhysicalNode)
			throws SecurityException, Exception {
		try {
			HttpSession session = getThreadLocalRequest().getSession(false);
			// verifico autorizzazione
			Operation operation = SecurityHelper.getOperation(
					AddPhysicalMachine.ID, session);
			operation.execute(new Object[] { serializablePhysicalNode });
			return true;
		} catch (SecurityException e) {
			throw new SecurityException(e.getMessage());
		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}

	public Boolean editPhysicalMachine(
			SerializablePhysicalNode serializablePhysicalNode)
			throws SecurityException, Exception {
		try {
			HttpSession session = getThreadLocalRequest().getSession(false);
			// verifico autorizzazione
			Operation operation = SecurityHelper.getOperation(
					EditPhysicalMachine.ID, session);
			operation.execute(new Object[] { serializablePhysicalNode });
			return true;
		} catch (SecurityException e) {
			throw new SecurityException(e.getMessage());
		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}

	public SerializableCluster getCluster() throws SecurityException, Exception {
		try {
			HttpSession session = getThreadLocalRequest().getSession(false);
			GetCluster operation = (GetCluster) SecurityHelper.getOperation(
					GetCluster.ID, session);

			Cluster cluster = (Cluster) operation.execute(null)[0];
			return SerializationHelper.toSerializableCluster(cluster);
		} catch (SecurityException e) {
			throw new SecurityException(e.getMessage());
		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}

	public SerializablePhysicalNode getPhysicalNode(String idPhysicalNode)
			throws SecurityException, Exception {
		try {
			HttpSession session = getThreadLocalRequest().getSession(false);
			// verifico autorizzazione
			Operation operation = SecurityHelper.getOperation(
					GetPhysicalMachine.ID, session);
			Object[] obj = operation.execute(new Object[] { idPhysicalNode });
			SerializablePhysicalNode sPhyNode = SerializationHelper
					.toSerializablePhysicalNode((PhysicalNode) obj[0]);
			return sPhyNode;
		} catch (SecurityException e) {
			throw new SecurityException(e.getMessage());
		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}

	public String[] getPMState(String pmId) throws SecurityException, Exception {
		// TODO
		return new String[] { "80%", "1516/2000", "202/500" };
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see neptune.web.client.services.ClusterService#getTask()
	 */
	public String[][] getTask() throws SecurityException, Exception {
		try {
			HttpSession session = getThreadLocalRequest().getSession(false);
			Operation operation = (GetTask) SecurityHelper.getOperation(
					GetTask.ID, session);
			String[][] result = (String[][]) operation.execute(null)[0];
			return result;

		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}

	public String[][] getVMsHostedByPM(String pmId) throws SecurityException,
			Exception {

		try {
			HttpSession session = getThreadLocalRequest().getSession(false);
			Operation operation = (GetVMsHostedOnPm) SecurityHelper
					.getOperation(GetVMsHostedOnPm.ID, session);

			String[][] result = (String[][]) operation
					.execute(new Object[] { pmId })[0];

			return result;

		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * neptune.web.client.services.ClusterService#getXenStatistic(java.lang.
	 * String)
	 */
	public String[][] getXenStatistic(String idPhysicalMachine)
			throws SecurityException, Exception {
		try {
			HttpSession session = getThreadLocalRequest().getSession(false);
			// verifico autorizzazione
			Operation operation = SecurityHelper.getOperation(
					GetXenStatistic.ID, session);
			Object[] result = operation
					.execute(new Object[] { idPhysicalMachine });
			return (String[][]) result[0];

		} catch (SecurityException e) {
			throw new SecurityException(e.getMessage());
		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}

	public String pauseNode(String nodeId) throws SecurityException, Exception {

		PhysicalNode machine = ApplicationManager.getApplicationManager()
				.getNeptuneManager().getCluster().getNodeHoster(nodeId);

		if (machine == null)
			throw new Exception("Unable to execute operation because the '"
					+ nodeId + "' hoster was not found.");

		return pauseNode(nodeId, machine.getId());
	}

	public String pauseNode(String nodeId, String pmId)
			throws SecurityException, Exception {
		try {

			Operation operation;
			HttpSession session = getThreadLocalRequest().getSession(false);

			String expId = NeptuneManager.getExpNameFromNodeFullID(nodeId);
			if (expId != null)
				operation = (PauseNode) SecurityHelper.getOperation(
						PauseNode.ID, expId, session);
			else
				operation = (PauseNode) SecurityHelper.getOperation(
						PauseNode.ID, session);

			Cluster cluster = ApplicationManager.getApplicationManager()
					.getNeptuneManager().getCluster();
			PhysicalNode machine = cluster.getNodeById(pmId);

			String result = (String) operation.execute(new Object[] { nodeId,
					machine })[0];

			return result;

		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}

	public String rebootNode(String nodeId) throws SecurityException, Exception {
		PhysicalNode machine = ApplicationManager.getApplicationManager()
				.getNeptuneManager().getCluster().getNodeHoster(nodeId);

		if (machine == null)
			throw new Exception("Unable to execute operation because the '"
					+ nodeId + "' hoster was not found.");

		return rebootNode(nodeId, machine.getId());
	}

	public String rebootNode(String nodeId, String pmId)
			throws SecurityException, Exception {
		try {
			Operation operation;
			HttpSession session = getThreadLocalRequest().getSession(false);

			String expId = NeptuneManager.getExpNameFromNodeFullID(nodeId);
			if (expId != null)
				operation = (RebootNode) SecurityHelper.getOperation(
						RebootNode.ID, expId, session);
			else
				operation = (RebootNode) SecurityHelper.getOperation(
						RebootNode.ID, session);

			Cluster cluster = ApplicationManager.getApplicationManager()
					.getNeptuneManager().getCluster();
			PhysicalNode machine = cluster.getNodeById(pmId);

			String result = (String) operation.execute(new Object[] { nodeId,
					machine })[0];

			return result;

		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see neptune.web.client.services.ClusterService#removeAllFinishedJobs()
	 */
	public Boolean removeAllFinishedJobs() throws SecurityException, Exception {
		try {
			HttpSession session = getThreadLocalRequest().getSession(false);
			// verifico autorizzazione
			Operation operation = SecurityHelper.getOperation(
					RemoveAllFinishedJobs.ID, session);
			Boolean result = (Boolean) operation.execute(null)[0];
			return result;
		} catch (SecurityException e) {
			throw new SecurityException(e.getMessage());
		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}

	public String removePhysicalMachine(String idPhysicalMachine)
			throws SecurityException, Exception {

		try {
			HttpSession session = getThreadLocalRequest().getSession(false);
			// verifico autorizzazione
			Operation operation = SecurityHelper.getOperation(
					RemovePhysicalMachine.ID, session);
			String result = (String) operation
					.execute(new Object[] { idPhysicalMachine })[0];
			return result;
		} catch (SecurityException e) {
			throw new SecurityException(e.getMessage());
		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}

	}

	public String startNode(String nodeId) throws SecurityException, Exception {
		PhysicalNode machine = ApplicationManager.getApplicationManager()
				.getNeptuneManager().getCluster().getNodeHoster(nodeId);

		if (machine == null)
			throw new Exception("Unable to execute operation because the '"
					+ nodeId + "' hoster was not found.");

		return startNode(nodeId, machine.getId());
	}

	public String startNode(String nodeId, String pmId)
			throws SecurityException, Exception {
		try {
			Operation operation;
			HttpSession session = getThreadLocalRequest().getSession(false);

			String expId = NeptuneManager.getExpNameFromNodeFullID(nodeId);
			if (expId != null)
				operation = (StartNode) SecurityHelper.getOperation(
						StartNode.ID, expId, session);
			else
				operation = (StartNode) SecurityHelper.getOperation(
						StartNode.ID, session);

			Cluster cluster = ApplicationManager.getApplicationManager()
					.getNeptuneManager().getCluster();
			PhysicalNode machine = cluster.getNodeById(pmId);

			String result = (String) operation.execute(new Object[] { nodeId,
					machine })[0];

			return result;

		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * neptune.web.client.services.ClusterService#savaNodeAsTemplate(java.lang
	 * .String)
	 */
	public String saveNodeAsTemplate(String nodeId, String templateName) throws SecurityException,
			Exception {
		try {
			Operation operation;
			HttpSession session = getThreadLocalRequest().getSession(false);

			String expId = NeptuneManager.getExpNameFromNodeFullID(nodeId);
			if (expId != null)
				operation = (SaveNodeAsTemplate) SecurityHelper.getOperation(
						SaveNodeAsTemplate.ID, expId, session);
			else
				operation = (SaveNodeAsTemplate) SecurityHelper.getOperation(
						SaveNodeAsTemplate.ID, session);

			PhysicalNode machine = ApplicationManager.getApplicationManager()
					.getNeptuneManager().getCluster().getNodeHoster(nodeId);

			String result = (String) operation.execute(new Object[] { nodeId,
					machine, templateName })[0];

			return result;

		} catch (Exception e) {
			Debug.printTrace(e);
			throw new Exception(e);
		}
	}
}
